package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"os/exec"

	pflag "github.com/spf13/pflag"
)

type selpgArgs struct {
	startPage  int
	endPage    int
	inFilename string
	pageLen    int
	pageType   bool
	printDest  string
}

var progname string

// ProcessArgs 解析输入参数，存入参数结构体中
func ProcessArgs(args *selpgArgs) {

	/* check the command-line arguments for validity */
	//return os.Args
	/* Not enough args, minimum command is "selpg -sstart_page -eend_page"  */
	if len(os.Args) < 3 {
		fmt.Fprintf(os.Stderr, "%s: not enough arguments\n", progname)
		Usage()
		os.Exit(1)
	}

	/* handle mandatory args first */
	var tmp string

	/* handle 1st arg - start page */
	tmp = os.Args[1]
	if tmp[0:2] != "-s" {
		fmt.Fprintf(os.Stderr, "%s: 1st arg should be -sstart_page\n", progname)
		Usage()
		os.Exit(2)
	}

	/* handle 2nd arg - end page */
	tmp = os.Args[2]
	if tmp[0:2] != "-e" {
		fmt.Fprintf(os.Stderr, "%s: 2nd arg should be -eend_page\n", progname)
		Usage()
		os.Exit(3)
	}

	/* Use pflag to bind each parameter */
	pflag.IntVarP(&args.startPage, "start", "s", -1, "Start Page.")
	pflag.IntVarP(&args.endPage, "end", "e", -1, "End Page.")
	pflag.IntVarP(&args.pageLen, "len", "l", 10, "Lines per Page.")
	pflag.BoolVarP(&args.pageType, "type", "f", false, "Form-feed-delimited")
	pflag.StringVarP(&args.printDest, "destination", "d", "", "Specific Printer")
	pflag.Parse()

	/* parse the final parameter, the input file */
	if pflag.NArg() > 0 {
		args.inFilename = string(pflag.Arg(0))
	} else {
		args.inFilename = ""
	}

	/* Check the value range of each parameter */
	if args.pageLen < 1 {
		fmt.Fprintf(os.Stderr, "%s: invalid page length %v\n", progname, args.pageLen)
		os.Exit(4)
		Usage()
	}
	if args.startPage < 1 {
		fmt.Fprintf(os.Stderr, "%s: invalid start page %v\n", progname, args.startPage)
		os.Exit(5)
		Usage()
	}
	if (args.startPage > args.endPage) || (args.endPage < 1) {
		fmt.Fprintf(os.Stderr, "%s: invalid end page %v\n", progname, args.endPage)
		os.Exit(6)
		Usage()
	}
	//return nil
}

// ProcessInput 根据参数设定输入输出源，将从输入源读取指定范围的页到输出源
func ProcessInput(args *selpgArgs) {

	var inFile *os.File
	var outFile io.WriteCloser
	var cmd *exec.Cmd
	pwd, _ := os.Getwd()

	/* set the input source */
	if args.inFilename == "" {
		inFile = os.Stdin
	} else {
		var inFileError error
		inFile, inFileError = os.Open(pwd + "/" + args.inFilename)
		if inFileError != nil {
			fmt.Fprintf(os.Stderr, "%s: could not open input file \"%s\"\n", progname, args.inFilename)
			os.Exit(7)
		}
	}

	/* set the output destination */
	if args.printDest == "" {
		outFile = os.Stdout
	} else {
		/* Use "cat" as a printer */
		cmd = exec.Command("cat")
		var outFileError error
		cmd.Stdout, outFileError = os.OpenFile(pwd+"/"+args.printDest, os.O_WRONLY|os.O_TRUNC, 0600)
		if outFileError != nil {
			fmt.Fprintf(os.Stderr, "%s: file not exist\n%s\n", progname, args.printDest)
			os.Exit(8)
		}
		outFile, _ = cmd.StdinPipe()
		cmd.Start()
	}

	/* begin one of two main loops based on page type */

	pageCount := 1
	buffer := bufio.NewReader(inFile)

	if args.pageType {

		for {
			line, err := buffer.ReadString('\f')

			if err != io.EOF && err != nil {
				fmt.Fprintf(os.Stderr, "%s: could not read file\n%s\n", progname, args.inFilename)
				os.Exit(9)
			}

			pageCount++

			if (pageCount >= args.startPage) && (pageCount <= args.endPage) {
				_, err := outFile.Write([]byte(line))

				if err != nil {
					fmt.Fprintf(os.Stderr, "%s: could not read file\n%v\n", progname, err)
					os.Exit(10)
				}
			}

			if err == io.EOF {
				break
			}
		}
		return
	}

	lineCount := 0

	for {

		line, err := buffer.ReadString('\n')

		if err != io.EOF && err != nil {
			fmt.Fprintf(os.Stderr, "%s: could not read file\n%s\n", progname, args.inFilename)
			os.Exit(9)
		}

		lineCount++

		if lineCount > args.pageLen {
			pageCount++
			lineCount = 1
		}

		if (pageCount >= args.startPage) && (pageCount <= args.endPage) {
			_, err := outFile.Write([]byte(line))

			if err != nil {
				fmt.Fprintf(os.Stderr, "%s: could not read file\n%v\n", progname, err)
				os.Exit(10)
			}
		}

		if err == io.EOF {
			break
		}
	}

}

//Usage 打印使用信息
func Usage() {

	fmt.Fprintf(os.Stderr, "\nUSAGE: %s -sstartPage -eendPage [ -f | -lpageLen ] [ -dprintDest ] [ inFilename ]\n", progname)

}

func main() {
	progname = os.Args[0]
	var args selpgArgs
	ProcessArgs(&args)
	ProcessInput(&args)
}
